package com.opengw.beans;

//~--- non-JDK imports --------------------------------------------------------

import com.opengw.beans.support.MessagesController;
import com.opengw.configuration.CertificateManager;
import com.opengw.configuration.ConfigurationManager;
import com.opengw.configuration.config.BasicAuthentication;
import com.opengw.configuration.entity.CertificateInfo;
import com.opengw.configuration.publish.BasicPublish;
import com.opengw.configuration.route.Route;
import com.opengw.configuration.services.PublishService;
import com.opengw.configuration.support.Base64;
import com.opengw.configuration.support.Constants;
import com.opengw.configuration.support.SSLCertificateCapturer;
import com.opengw.http.HTTPConnection;
import com.opengw.http.HTTPConstants;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

//~--- JDK imports ------------------------------------------------------------

import javax.net.ssl.SSLHandshakeException;

/**
 * Class description
 *
 *
 * @version        1, 11/06/28
 * @author         ismozen
 */
@Component
@Scope("view")
@Qualifier("publishBasicBean")
public class PublishBasicBean {

	@Autowired
	private PublishService publishService;
    /**
     *
     * state = 0 is initialize view and set the request path
     * state = 1 is check the connection to address
     * state = 2 is check the SSL certificate of address
     * state = 3 is set username and password if basic authantication is needed
     * state = 4 is set avaiable request methods
     * state = 5 is successfully added message
     *
     */
    private int state = 0;

    /** Field description */
    private CertificateInfo certificateInfo;

    /** Field description */
    @Autowired
    transient private MessagesController messagesController;

    /** Field description */
    private String password;

    /** Field description */
    private String routeURL;

    /** Field description */
    private String username;
    
    private String publishName;
    
    private String requestPath;
    
    private boolean postAvaiable;
    private boolean getAvaiable;
    private boolean isAuthNeed;
    
    
    public PublishBasicBean(){
    }

    /**
     * Method description
     *
     */
    public void checkURL() {
    	boolean hasError = false;
    	if(routeURL == null || routeURL.equals("") || (!routeURL.startsWith("http://") && !routeURL.startsWith("https://"))){
    		hasError = true;
    		messagesController.addError("publishForm:routeURL", "dfgd", "ERROR");
    	}
    	
    	if(requestPath == null || requestPath.equals("")){
    		hasError = true;
    		messagesController.addError("publishForm:requestPath", "sdf", "ERROR");
    	}
    	
    	if(publishName == null || publishName.equals("")){
    		hasError = true;
    		messagesController.addError("publishForm:publishName", "ss", "ERROR");
    	}
    	ConfigurationManager configurationManager = ConfigurationManager.getConfigurationManager();
    	Route route = configurationManager.getRoute("/route/" + requestPath);
    	if(route != null){
    		hasError = true;
    		messagesController.addError("publishForm:requestPath", "sss", "UNAVALIABLE NAME");
    	}
    	
    	if(hasError)
    		return;
    	
    	
    	
        if ((this.state == 0) || (this.state == 1) || (this.state == 3)) {
        	try{
	        	HTTPConnection conn = new HTTPConnection(this.routeURL);
	        	conn.connect();
	        	if(conn.getHTTPCode() == 200){
	        		this.state = 4;
	        	} else if(conn.getHTTPCode() == 401)
	        		this.state = 3;
	        	else{
	        		this.state = 0;
	        		messagesController.addError("HTTP" + conn.getHTTPCode() + " can not access address", "");
        		}
        	} catch (SSLHandshakeException e) {
        		getCertificateFromURL();
        	} catch (Exception e) {
        		messagesController.addError(e.getMessage(), "");
			}
        }
        
    }
    
    public void basicAuthCheckURL(){
    	if(this.state == 3){
    		try{
    			HTTPConnection conn = new HTTPConnection(this.routeURL);
    			String authHeader = "Basic ";
    			Base64 base64 = new Base64();
    			String encodedToken = base64.encode((this.username + ":" + this.password).getBytes());
    			authHeader += encodedToken;
    			conn.setRequestHeader(HTTPConstants.AUTHORIZATION_HEADER, authHeader);
    			conn.connect();
	        	if(conn.getHTTPCode() == 200){
	        		this.state = 4;
	        		isAuthNeed = true;
	        	} else if(conn.getHTTPCode() == 401)
	        		this.state = 3;
	        	else{
	        		this.state = 0;
	        		messagesController.addError("HTTP" + conn.getHTTPCode() + " can not access address", "");
        		}
    		} catch (Exception e) {
    			messagesController.addError(e.getMessage(), "");
			}
    	}
    }
    
    public void setConfiguration(){
    	if(!this.postAvaiable && !this.getAvaiable){
    		messagesController.addWarn("You must choose one", "");
    		return;
    	}
    	
    	addBasicPublish();
    	this.state = 5;
    	messagesController.addInfo("SUCCESFULLY ADDED", "SUCCESFULLY ADDED DETAIL");
    }
    
    private void addBasicPublish(){
    	BasicPublish publish = new BasicPublish();
    	publish.setPublishName(publishName);
    	ConfigurationManager configurationManager = ConfigurationManager.getConfigurationManager();
    	Route route = new Route();
    	route.setConnectTimeOut(configurationManager.getDefaultConnectTimeOut());
    	route.setReadTimeOut(configurationManager.getDefaultReadTimeOut());
    	route.setRequestPath(Constants.ROUTE_BASIC_PATH + requestPath);
    	route.setRouteURL(routeURL);
    	route.setAvailableMethods(getAvaiableMethods());
    	
    	if(isAuthNeed){
    		BasicAuthentication authenticationConfig = new BasicAuthentication(false);
    		authenticationConfig.setUsername(username);
    		authenticationConfig.setPassword(password);
    		route.addRouteConfig(authenticationConfig);
    	}
    	
    	publish.setRoute(route);
    	
    	publishService.savePublish(publish);
    	
    	configurationManager.addPublish(publish);
    }
    
    private void getCertificateFromURL(){
    	if (this.routeURL.startsWith(HTTPConstants.HTTPS_PROTOCOL) && (this.state == 0)) {
            try {
                SSLCertificateCapturer certificateCapturer = new SSLCertificateCapturer(this.routeURL);
                this.certificateInfo = new CertificateInfo(certificateCapturer.captureSSLCertificate());
                this.state       = 2;
            } catch (Exception e) {
            	messagesController.addError(e.getMessage(), "");
            }
        }
    }
    
    public void addCertificaToTrustStore(){
    	CertificateManager manager = CertificateManager.getCertificateManager();
    	try{
    		manager.addCertificate(this.certificateInfo.getCertificate());
    	} catch (Exception e) {
    		messagesController.addError(e.getMessage(), "");
		}
    	this.state = 1;
    	checkURL();
    }
    
    private String getAvaiableMethods(){
    	String methods = "";
    	if(this.postAvaiable){
    		methods += HTTPConstants.HTTP_METHOD_POST;
    	}
    	if(methods.equals(""))
    		methods += ",";
    	if(this.getAvaiable){
    		methods += HTTPConstants.HTTP_METHOD_GET;
    	}
    	
    	return methods;
    }
    
    public void cancelAddCertificate(){
    	this.state = 0;
    }
    

    /**
     * Method description
     *
     *
     * @param state
     */
    public void setState(int state) {
        this.state = state;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public int getState() {
        return state;
    }

    /**
     * Method description
     *
     *
     * @param routeURL
     */
    public void setRouteURL(String routeURL) {
        this.routeURL = routeURL;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public String getRouteURL() {
        return routeURL;
    }

    /**
     * Method description
     *
     *
     * @param certificate
     */
    public void setCertificateInfo(CertificateInfo certificateInfo) {
        this.certificateInfo = certificateInfo;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public CertificateInfo getCertificateInfo() {
        return certificateInfo;
    }

    /**
     * Method description
     *
     *
     * @param username
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public String getUsername() {
        return username;
    }

    /**
     * Method description
     *
     *
     * @param password
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * Method description
     *
     *
     * @return
     */
    public String getPassword() {
        return password;
    }

	public void setPublishName(String publishName) {
		this.publishName = publishName;
	}

	public String getPublishName() {
		return publishName;
	}

	public void setRequestPath(String requestPath) {
		this.requestPath = requestPath;
	}

	public String getRequestPath() {
		return requestPath;
	}

	public void setPostAvaiable(boolean postAvaiable) {
		this.postAvaiable = postAvaiable;
	}

	public boolean isPostAvaiable() {
		return postAvaiable;
	}

	public void setGetAvaiable(boolean getAvaiable) {
		this.getAvaiable = getAvaiable;
	}

	public boolean isGetAvaiable() {
		return getAvaiable;
	}

}


//~ Formatted by Jindent --- http://www.jindent.com
